package com.heima.article.service.impl;

import com.heima.article.pojo.ApArticle;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.ApFreeMarkerService;
import com.heima.common.constants.message.Article2EsConstants;
import com.heima.common.util.JsonUtils;
import com.heima.file.service.MinioService;
import com.heima.model.media.dtos.WmNewsContentItem;
import freemarker.template.Configuration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Fuqiang
 * @since :2023-03-28
 */
@Slf4j
@Service
public class ApFreeMarkerServiceImpl implements ApFreeMarkerService {


    @Autowired
    MinioService minioService;

    @Autowired
    Configuration configuration;

    @Lazy
    @Autowired
    ApArticleService articleService;

    @Autowired
    KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 异步生成Html文件, 上传minio, 并回填地址
     *
     * @param content   文章内容
     * @param articleId 文章id
     */
    @Async("taskExecutor")
    @Override
    public void asyncCreateHtmlAndUploadToMinio(String content, Long articleId) {
        // 这段代码用于防止因异步操作导致的回填静态页面url先于article生成落库
/*        int i = 0;
        while (++i <= 3) {
            ApArticle apArticleDB = articleService.getById(articleId);
            if (apArticleDB == null) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                break;
            }
        }
        // 如果重试次数超过三次, 记录日志, 结束
        if (i > 3) {
            log.error("apArticle落库超时,重试次数达到上限");
            // 这里可能需要起一个定时任务去重新生成?
            return;
        }*/
        // 生成Html文件 并返回一个 inputStream用于minio上传
        ByteArrayInputStream inputStream = createStaticHtmlFile(content);
        // 上传minio
        String htmlFileName = articleId + ".html";
        String staticHtmlUrl = minioService.uploadHtmlFile("", htmlFileName, inputStream);

        // 回填地址
        ApArticle apArticle = new ApArticle();
        apArticle.setId(articleId);
        apArticle.setStaticUrl(staticHtmlUrl);
        articleService.updateById(apArticle);

        // 发送kafka消息 将articleId发送给search服务进行增量添加
        kafkaTemplate.send(Article2EsConstants.ARTICLE_2_ES_TOPIC, "" + apArticle.getId());
    }

    /**
     * 生成静态Html文件 并返回一个 inputStream
     *
     * @param content
     * @return inputStream 用于上传至minio
     */
    private ByteArrayInputStream createStaticHtmlFile(String content) {
        List<WmNewsContentItem> wmNewsContentItems = JsonUtils.toList(content, WmNewsContentItem.class);
        Map<String, Object> htmlDataModelMap = new HashMap<>(1);
        htmlDataModelMap.put("content", wmNewsContentItems);

        StringWriter writer = new StringWriter();
        try {
            configuration.getTemplate("article.ftl").process(htmlDataModelMap, writer);
        } catch (Exception e) {
            log.error("FreeMarker生成静态文件出现异常:{}", ExceptionUtils.getStackTrace(e));
        }
        // 将write流转为inputStream 用于上传minio
        byte[] htmlBytes = writer.toString().getBytes(StandardCharsets.UTF_8);

        return new ByteArrayInputStream(htmlBytes);

    }
}
